// file：arch/x86/hardware/console.c
// autor:jiangxinpeng
// time:2021.2.2
// copyright:(C) 2020-2050 by Jiang xinpeng. All rights reserved.

#include <arch/console.h>
#include <arch/pymem.h>
#include <arch/cursor.h>
#include <os/spinlock.h>
#include <arch/text.h>
#include <lib/string.h>

console_t console;

DEFINE_SPIN_LOCK(console_lock);

// system console
void ConsoleInit()
{
    // init text mode console argument
    console.mode = CONSOLE_MODE_TEXT;
    console.x = CONSOLE_X;
    console.y = CONSOLE_Y;
    console.high = CONSOLE_HIGH;
    console.weight = CONSOLE_WEIGHT;
    console.size = CONSOLE_HIGH * CONSOLE_WEIGHT;
    console.background = TEXT_BACKGROUNTCOLOR_BLACK;
    console.front = TEXT_FRONTCOLOR_WHITE;
    console.cur_line = 0;       // current windows line
    console.cur_list = 0;       // current windows list
    console.scrollposition = 0; // scroll position
    // init cursor
    SetCursor(0, 0);
    // clean screen
    ConsoleCleanScreen();
}

void ConsolePutChar(char ch)
{
    int position;

    // SpinLock(&console_lock);

    if (console.cur_line < CONSOLE_Y_MAX)
    {
        if (console.cur_list < CONSOLE_X_MAX)
        {
            if (ch != '\n')
            {
                // put char
                TextPutChar(ch, CONSOLE_COLOR_MASK(console.background, console.front));
                // next char
                console.cur_list++;

#if CONSOLE_HAS_CURSOR
                // update cursor
                position = ReadCursor();
                WriteCursor(position + 1);
#endif

                if (console.cur_list >= CONSOLE_X_MAX)
                {
                    console.cur_line++;
                    console.cur_list = 0;
                }
            }
            else
            {
                console.cur_line++;
                console.cur_list = 0;

#if CONSOLE_HAS_CURSOR
                // next line
                position = ReadCursor();
                WriteCursor(position + (CHARS_PER_LINE - (position % CHARS_PER_LINE)));
#endif
            }
        }
        else
        {
            // above line
            console.cur_line++;
            console.cur_list = 0;
            // next line
            position = ReadCursor();
            WriteCursor(position + (CHARS_PER_LINE - (position % CHARS_PER_LINE)));
        }
    }

    if (console.cur_line >= console.high)
    {
        ConsoleScrollScreen();
        // go to last line
        console.cur_line--;
        console.cur_list = 0;
        SetCursor(0, console.cur_line);
    }
    // SpinUnlock(&console_lock);
}

// put a string to console
void ConsolePutString(char *str)
{
    if (str != NULL)
    {
        while (*str++ != '\0')
        {
            ConsolePutChar(*str);
        }
    }
}

// clean console screen
void ConsoleCleanScreen()
{
    char ch = 0x20;

    // clean console
    TextClearArea(console.x, console.y, console.size, CONSOLE_COLOR_MASK(TEXT_BACKGROUNTCOLOR_BLACK, TEXT_FRONTCOLOR_WHITE));

    // reset console
    console.cur_line = 0;
    console.cur_list = 0;

    // reset cursor
    SetCursor(0, 0);
}

// scroll screen
// mode:
// 0 up
// 1 down
void ConsoleScrollScreen()
{
    uint8_t *src;
    uint8_t *targe;
    int i, j, k;
    uint8_t *buff = page_enable ? TEXT_BUFFER_ADDRESS + PAGE_HIGH_BASE : TEXT_BUFFER_ADDRESS;

    for (i = 1; i < 25; i++)
    {
        j = i - 1;
        src = buff + i * 80 * 2;
        targe = buff + j * 80 * 2;
        for (k = 0; k < 80; k++)
        {
            *(targe + k * 2) = *(src + k * 2);
            *(targe + k * 2 + 1) = *(src + k * 2 + 1);
        }
    }

    // clear empty line context
    for (k = 0; k < 80; k++)
    {
        *(src + k * 2) = 0x20;
        *(src + k * 2 + 1) = CONSOLE_COLOR_MASK(TEXT_BACKGROUNTCOLOR_BLACK, TEXT_FRONTCOLOR_WHITE);
    }
}
